package website.haicheng.server.config;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import cn.hutool.system.SystemUtil;
import website.haicheng.server.handlers.ServerHandler;
import website.haicheng.server.util.MessageDecode;
import website.haicheng.server.util.MessageEncode;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * @Author: 582895699@qq.com
 * @Desctription: Netty配置
 * @Date: Created in 2021/12/1 16:10
 */
@Slf4j
@Configuration
public class NettyServer {

    public EventLoopGroup bossGroup;

    public EventLoopGroup workGroup;
    /**
     * 配置bossGroup线程池前缀
     */
    public static final ThreadFactory BOSS_THREAD_FACTORY = new ThreadFactoryBuilder().setNamePrefix("boss-").build();
    /**
     * 配置workGroup线程池前缀
     */
    public static final ThreadFactory WORK_THREAD_FACTORY = new ThreadFactoryBuilder().setNamePrefix("work-").build();


    @Value(value = "${netty.port}")
    public Integer serverPort;

    @Resource
    private ServerHandler serverMessageHandler;


    @PostConstruct
    public void init() {
        createEventLoop();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workGroup)
                .channel(isLinux() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childHandler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new ReadTimeoutHandler(3, TimeUnit.MINUTES));
                        pipeline.addLast("encode", new MessageEncode());
                        pipeline.addLast("decode", new MessageDecode());
                        pipeline.addLast(new IdleStateHandler(5, 5, 5));
                        pipeline.addLast("serverMessageHandler", serverMessageHandler);
                    }
                });

        ChannelFuture channelFuture = serverBootstrap.bind(serverPort).syncUninterruptibly();
        if (channelFuture.isSuccess()) {
            log.info("**********  【Netty启动成功，端口：{}】  **********", serverPort);
        }
    }


    /**
     * 创建EventLoopGroup
     */
    private void createEventLoop() {
        if (isLinux()) {
            bossGroup = new EpollEventLoopGroup(BOSS_THREAD_FACTORY);
            workGroup = new EpollEventLoopGroup(WORK_THREAD_FACTORY);
            return;
        }
        bossGroup = new NioEventLoopGroup(BOSS_THREAD_FACTORY);
        workGroup = new NioEventLoopGroup(WORK_THREAD_FACTORY);
    }

    /**
     * 是否是linux系统
     *
     * @return boolean
     */
    private boolean isLinux() {
        return SystemUtil.getOsInfo().isLinux();
    }
}
